package services

import (
	"encoding/json"
	"fmt"
	"go-vue3-ts-nativeUI-unocss/internal/models"
	"os"
	"path/filepath"
	"sync"
	"time"
)

// LogService 日志服务
type LogService struct {
	logDir      string
	logFile     *os.File
	encoder     *json.Encoder
	mu          sync.RWMutex
	memoryLogs  []models.LogEntry
	maxMemoryLogs int
}

var (
	logServiceInstance *LogService
	logServiceOnce     sync.Once
)

// GetLogService 获取日志服务单例
func GetLogService() *LogService {
	logServiceOnce.Do(func() {
		// 获取日志目录（用户配置目录）
		configDir, err := os.UserConfigDir()
		if err != nil {
			configDir = "."
		}
		logDir := filepath.Join(configDir, "go-vue3-ts-nativeUI-unocss", "logs")

		// 确保日志目录存在
		if err := os.MkdirAll(logDir, 0755); err != nil {
			panic(fmt.Sprintf("创建日志目录失败: %v", err))
		}

		// 创建日志文件（按日期）
		today := time.Now().Format("2006-01-02")
		logPath := filepath.Join(logDir, fmt.Sprintf("app-%s.log", today))

		logFile, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
		if err != nil {
			panic(fmt.Sprintf("打开日志文件失败: %v", err))
		}

		logServiceInstance = &LogService{
			logDir:        logDir,
			logFile:       logFile,
			encoder:       json.NewEncoder(logFile),
			memoryLogs:    make([]models.LogEntry, 0),
			maxMemoryLogs: 300, // 内存中最多保存 300 条日志
		}

		// 启动日志清理协程（每天清理 7 天前的日志）
		go logServiceInstance.startCleanupRoutine()
	})

	return logServiceInstance
}

// Log 记录日志
func (s *LogService) Log(level models.LogLevel, module, message string, data map[string]interface{}) {
	entry := models.LogEntry{
		Time:    time.Now(),
		Level:   level,
		Module:  module,
		Message: message,
		Data:    data,
	}

	// Debug 级别只输出到控制台，不保存到文件和内存
	if level == models.LogLevelDebug {
		fmt.Printf("[DEBUG] [%s] %s %v\n", module, message, data)
		return
	}

	s.mu.Lock()
	defer s.mu.Unlock()

	// 写入文件（Info、Warn、Error、Fatal）
	if err := s.encoder.Encode(entry); err != nil {
		// 如果写入失败，尝试重新打开文件
		s.reopenLogFile()
		_ = s.encoder.Encode(entry)
	}

	// 保存到内存
	s.memoryLogs = append(s.memoryLogs, entry)
	if len(s.memoryLogs) > s.maxMemoryLogs {
		// 移除最旧的日志
		s.memoryLogs = s.memoryLogs[1:]
	}
}

// Debug 记录 Debug 级别日志
func (s *LogService) Debug(module, message string, data map[string]interface{}) {
	s.Log(models.LogLevelDebug, module, message, data)
}

// Info 记录 Info 级别日志
func (s *LogService) Info(module, message string, data map[string]interface{}) {
	s.Log(models.LogLevelInfo, module, message, data)
}

// Warn 记录 Warn 级别日志
func (s *LogService) Warn(module, message string, data map[string]interface{}) {
	s.Log(models.LogLevelWarn, module, message, data)
}

// Error 记录 Error 级别日志
func (s *LogService) Error(module, message string, data map[string]interface{}) {
	s.Log(models.LogLevelError, module, message, data)
}

// Fatal 记录 Fatal 级别日志
func (s *LogService) Fatal(module, message string, data map[string]interface{}) {
	s.Log(models.LogLevelFatal, module, message, data)
}

// GetLogs 获取日志
func (s *LogService) GetLogs(query models.LogQuery) models.LogResponse {
	s.mu.RLock()
	defer s.mu.RUnlock()

	limit := query.Limit
	if limit <= 0 {
		limit = 100
	}
	if limit > 1000 {
		limit = 1000
	}

	var filteredLogs []models.LogEntry

	for _, log := range s.memoryLogs {
		// 级别过滤
		if query.Level != "" && string(log.Level) != query.Level {
			continue
		}

		// 模块过滤
		if query.Module != "" && log.Module != query.Module {
			continue
		}

		// 时间过滤
		if query.StartTime != nil && log.Time.Before(*query.StartTime) {
			continue
		}
		if query.EndTime != nil && log.Time.After(*query.EndTime) {
			continue
		}

		filteredLogs = append(filteredLogs, log)
	}

	// 限制返回数量（取最新的）
	total := len(filteredLogs)
	if len(filteredLogs) > limit {
		filteredLogs = filteredLogs[len(filteredLogs)-limit:]
	}

	return models.LogResponse{
		Logs:  filteredLogs,
		Total: total,
	}
}

// ClearLogs 清空内存中的日志
func (s *LogService) ClearLogs() {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.memoryLogs = make([]models.LogEntry, 0)
}

// reopenLogFile 重新打开日志文件（用于日志轮转）
func (s *LogService) reopenLogFile() {
	if s.logFile != nil {
		_ = s.logFile.Close()
	}

	today := time.Now().Format("2006-01-02")
	logPath := filepath.Join(s.logDir, fmt.Sprintf("app-%s.log", today))

	logFile, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err == nil {
		s.logFile = logFile
		s.encoder = json.NewEncoder(logFile)
	}
}

// startCleanupRoutine 启动日志清理协程
func (s *LogService) startCleanupRoutine() {
	ticker := time.NewTicker(24 * time.Hour)
	defer ticker.Stop()

	for range ticker.C {
		s.cleanupOldLogs()
	}
}

// cleanupOldLogs 清理旧日志（保留 5 天）
func (s *LogService) cleanupOldLogs() {
	cutoffTime := time.Now().AddDate(0, 0, -5)

	entries, err := os.ReadDir(s.logDir)
	if err != nil {
		return
	}

	for _, entry := range entries {
		if entry.IsDir() {
			continue
		}

		info, err := entry.Info()
		if err != nil {
			continue
		}

		if info.ModTime().Before(cutoffTime) {
			logPath := filepath.Join(s.logDir, entry.Name())
			_ = os.Remove(logPath)
		}
	}
}

